"""
用户认证相关的工具函数

包含获取客户端IP、解析用户代理、创建登录日志等辅助功能。
"""
import re
import logging
from django.utils import timezone
from .models import LoginLog

# 获取日志记录器
logger = logging.getLogger('accounts')


def get_client_ip(request):
    """
    获取客户端真实IP地址
    
    考虑代理服务器的情况，优先获取真实IP
    
    Args:
        request: Django请求对象
        
    Returns:
        str: 客户端IP地址
    """
    # 获取代理转发的真实IP
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        # 如果有多个IP，取第一个
        ip = x_forwarded_for.split(',')[0].strip()
    else:
        # 直接连接的IP
        ip = request.META.get('REMOTE_ADDR')
    
    return ip or '127.0.0.1'


def parse_user_agent(user_agent_string):
    """
    解析用户代理字符串，提取浏览器和操作系统信息
    
    Args:
        user_agent_string: 用户代理字符串
        
    Returns:
        dict: 包含浏览器和操作系统信息的字典
    """
    if not user_agent_string:
        return {
            'browser': 'Unknown',
            'browser_version': '',
            'os': 'Unknown',
            'device': 'Unknown'
        }
    
    # 浏览器检测
    browser_patterns = {
        'Chrome': r'Chrome/([\d.]+)',
        'Firefox': r'Firefox/([\d.]+)',
        'Safari': r'Safari/([\d.]+)',
        'Edge': r'Edge/([\d.]+)',
        'Opera': r'Opera/([\d.]+)',
        'IE': r'MSIE ([\d.]+)'
    }
    
    browser = 'Unknown'
    browser_version = ''
    
    for name, pattern in browser_patterns.items():
        match = re.search(pattern, user_agent_string)
        if match:
            browser = name
            browser_version = match.group(1)
            break
    
    # 操作系统检测
    os_patterns = {
        'Windows': r'Windows NT ([\d.]+)',
        'macOS': r'Mac OS X ([\d_]+)',
        'Linux': r'Linux',
        'Android': r'Android ([\d.]+)',
        'iOS': r'OS ([\d_]+)'
    }
    
    os_name = 'Unknown'
    
    for name, pattern in os_patterns.items():
        if re.search(pattern, user_agent_string):
            os_name = name
            break
    
    # 设备类型检测
    device = 'Desktop'
    if re.search(r'Mobile|Android|iPhone|iPad', user_agent_string):
        device = 'Mobile'
    elif re.search(r'Tablet|iPad', user_agent_string):
        device = 'Tablet'
    
    return {
        'browser': browser,
        'browser_version': browser_version,
        'os': os_name,
        'device': device
    }


def create_login_log(user, request, status='success', action='login', failure_reason=''):
    """
    创建登录日志记录
    
    Args:
        user: 用户对象
        request: Django请求对象
        status: 登录状态 ('success', 'failed', 'blocked')
        action: 操作类型 ('login', 'register', 'logout')
        failure_reason: 失败原因（可选）
        
    Returns:
        LoginLog: 创建的登录日志对象
    """
    try:
        # 获取客户端信息
        ip_address = get_client_ip(request)
        user_agent = request.META.get('HTTP_USER_AGENT', '')
        
        # 创建登录日志
        login_log = LoginLog.objects.create(
            user=user,
            ip_address=ip_address,
            user_agent=user_agent,
            status=status,
            failure_reason=failure_reason
        )
        
        # 记录日志
        logger.info(
            f"登录日志创建: 用户={user.username}, IP={ip_address}, "
            f"状态={status}, 操作={action}"
        )
        
        return login_log
        
    except Exception as e:
        logger.error(f"创建登录日志失败: {str(e)}")
        return None


def validate_password_strength(password):
    """
    验证密码强度
    
    Args:
        password: 密码字符串
        
    Returns:
        tuple: (是否有效, 错误信息列表)
    """
    errors = []
    
    # 长度检查
    if len(password) < 8:
        errors.append('密码长度至少需要8位字符')
    
    # 包含字母检查
    if not re.search(r'[a-zA-Z]', password):
        errors.append('密码必须包含字母')
    
    # 包含数字检查
    if not re.search(r'\d', password):
        errors.append('密码必须包含数字')
    
    # 包含特殊字符检查（可选）
    # if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
    #     errors.append('密码建议包含特殊字符')
    
    return len(errors) == 0, errors


def generate_verification_code(length=6):
    """
    生成验证码
    
    Args:
        length: 验证码长度
        
    Returns:
        str: 验证码字符串
    """
    import random
    import string
    
    # 生成数字验证码
    return ''.join(random.choices(string.digits, k=length))


def mask_sensitive_info(info, info_type='email'):
    """
    脱敏敏感信息
    
    Args:
        info: 敏感信息字符串
        info_type: 信息类型 ('email', 'phone')
        
    Returns:
        str: 脱敏后的字符串
    """
    if not info:
        return ''
    
    if info_type == 'email':
        # 邮箱脱敏：保留前2位和@后的域名
        if '@' in info:
            local, domain = info.split('@', 1)
            if len(local) > 2:
                masked_local = local[:2] + '*' * (len(local) - 2)
                return f"{masked_local}@{domain}"
        return info
    
    elif info_type == 'phone':
        # 手机号脱敏：保留前3位和后4位
        if len(info) == 11:
            return f"{info[:3]}****{info[-4:]}"
        return info
    
    return info


def custom_exception_handler(exc, context):
    """
    自定义异常处理程序
    
    为Django REST Framework提供统一的异常处理，
    返回标准化的错误响应格式。
    
    Args:
        exc: 异常对象
        context: 异常上下文
        
    Returns:
        Response: 标准化的错误响应
    """
    from rest_framework.views import exception_handler
    from rest_framework.response import Response
    from rest_framework import status
    
    # 调用DRF默认的异常处理程序
    response = exception_handler(exc, context)
    
    if response is not None:
        # 自定义错误响应格式
        custom_response_data = {
            'success': False,
            'message': '请求处理失败',
            'error_code': response.status_code,
            'errors': response.data
        }
        
        # 根据不同的错误类型提供更友好的消息
        if response.status_code == 400:
            custom_response_data['message'] = '请求参数错误'
        elif response.status_code == 401:
            custom_response_data['message'] = '身份验证失败'
        elif response.status_code == 403:
            custom_response_data['message'] = '权限不足'
        elif response.status_code == 404:
            custom_response_data['message'] = '资源不存在'
        elif response.status_code == 500:
            custom_response_data['message'] = '服务器内部错误'
        
        response.data = custom_response_data
    
    return response